use std::sync::Arc;

use async_trait::async_trait;

use super::{
    BootstrapContext, BootstrapResult, DataSourceProvider, EventHandlerProvider, ExtensionProvider, ForgeConfigProvider, MetadataProvider,
    MiddlewareProvider, RuleProvider,
};

/// 阶段接口
///
/// 所有阶段都需要提供名称与执行逻辑，便于统一调度与记录。
#[async_trait]
pub trait BootstrapStage: Send + Sync {
    fn name(&self) -> &'static str;
    async fn execute(
        &self,
        ctx: &mut BootstrapContext,
    ) -> BootstrapResult<()>;
}

/// Schema 阶段包装
struct SchemaStageImpl {
    provider: Arc<dyn ExtensionProvider>,
}

impl SchemaStageImpl {
    fn new(provider: Arc<dyn ExtensionProvider>) -> Self {
        Self { provider }
    }
}

#[async_trait]
impl BootstrapStage for SchemaStageImpl {
    fn name(&self) -> &'static str {
        self.provider.name()
    }

    async fn execute(
        &self,
        ctx: &mut BootstrapContext,
    ) -> BootstrapResult<()> {
        let extensions = self.provider.provide(ctx.profile()).await?;
        ctx.push_extensions(extensions);
        Ok(())
    }
}

/// 规则阶段包装
struct RuleStageImpl {
    provider: Arc<dyn RuleProvider>,
}

impl RuleStageImpl {
    fn new(provider: Arc<dyn RuleProvider>) -> Self {
        Self { provider }
    }
}

#[async_trait]
impl BootstrapStage for RuleStageImpl {
    fn name(&self) -> &'static str {
        self.provider.name()
    }

    async fn execute(
        &self,
        ctx: &mut BootstrapContext,
    ) -> BootstrapResult<()> {
        let loader = self.provider.provide(ctx.profile()).await?;
        ctx.set_rule_loader(loader);
        Ok(())
    }
}

/// 元数据阶段包装
struct MetadataStageImpl {
    provider: Arc<dyn MetadataProvider>,
}

impl MetadataStageImpl {
    fn new(provider: Arc<dyn MetadataProvider>) -> Self {
        Self { provider }
    }
}

#[async_trait]
impl BootstrapStage for MetadataStageImpl {
    fn name(&self) -> &'static str {
        self.provider.name()
    }

    async fn execute(
        &self,
        ctx: &mut BootstrapContext,
    ) -> BootstrapResult<()> {
        let delta = self.provider.provide(ctx.profile()).await?;
        ctx.metadata_mut().extend(delta);
        Ok(())
    }
}

/// 数据源阶段包装
struct DataSourceStageImpl {
    provider: Arc<dyn DataSourceProvider>,
}

impl DataSourceStageImpl {
    fn new(provider: Arc<dyn DataSourceProvider>) -> Self {
        Self { provider }
    }
}

#[async_trait]
impl BootstrapStage for DataSourceStageImpl {
    fn name(&self) -> &'static str {
        self.provider.name()
    }

    async fn execute(
        &self,
        ctx: &mut BootstrapContext,
    ) -> BootstrapResult<()> {
        let profile = ctx.profile().clone();
        self.provider.configure(&profile, ctx).await
    }
}

/// EventHandler 阶段包装
struct EventHandlerStageImpl {
    provider: Arc<dyn EventHandlerProvider>,
}

impl EventHandlerStageImpl {
    fn new(provider: Arc<dyn EventHandlerProvider>) -> Self {
        Self { provider }
    }
}

#[async_trait]
impl BootstrapStage for EventHandlerStageImpl {
    fn name(&self) -> &'static str {
        self.provider.name()
    }

    async fn execute(
        &self,
        ctx: &mut BootstrapContext,
    ) -> BootstrapResult<()> {
        let handlers = self.provider.provide(ctx.profile()).await?;
        for handler in handlers {
            ctx.add_event_handler(handler);
        }
        Ok(())
    }
}

/// Middleware 阶段包装
struct MiddlewareStageImpl {
    provider: Arc<dyn MiddlewareProvider>,
}

impl MiddlewareStageImpl {
    fn new(provider: Arc<dyn MiddlewareProvider>) -> Self {
        Self { provider }
    }
}

#[async_trait]
impl BootstrapStage for MiddlewareStageImpl {
    fn name(&self) -> &'static str {
        self.provider.name()
    }

    async fn execute(
        &self,
        ctx: &mut BootstrapContext,
    ) -> BootstrapResult<()> {
        let stack = self.provider.provide(ctx.profile()).await?;
        ctx.set_middleware_stack(stack);
        Ok(())
    }
}

/// 快捷构造各类阶段
pub fn schema_stage<P>(provider: P) -> Box<dyn BootstrapStage>
where
    P: ExtensionProvider + 'static,
{
    Box::new(SchemaStageImpl::new(Arc::new(provider)))
}

pub fn schema_stage_from_arc(provider: Arc<dyn ExtensionProvider>) -> Box<dyn BootstrapStage> {
    Box::new(SchemaStageImpl::new(provider))
}

pub fn rule_stage<P>(provider: P) -> Box<dyn BootstrapStage>
where
    P: RuleProvider + 'static,
{
    Box::new(RuleStageImpl::new(Arc::new(provider)))
}

pub fn rule_stage_from_arc(provider: Arc<dyn RuleProvider>) -> Box<dyn BootstrapStage> {
    Box::new(RuleStageImpl::new(provider))
}

pub fn metadata_stage<P>(provider: P) -> Box<dyn BootstrapStage>
where
    P: MetadataProvider + 'static,
{
    Box::new(MetadataStageImpl::new(Arc::new(provider)))
}

pub fn metadata_stage_from_arc(provider: Arc<dyn MetadataProvider>) -> Box<dyn BootstrapStage> {
    Box::new(MetadataStageImpl::new(provider))
}

pub fn event_handler_stage<P>(provider: P) -> Box<dyn BootstrapStage>
where
    P: EventHandlerProvider + 'static,
{
    Box::new(EventHandlerStageImpl::new(Arc::new(provider)))
}

pub fn event_handler_stage_from_arc(provider: Arc<dyn EventHandlerProvider>) -> Box<dyn BootstrapStage> {
    Box::new(EventHandlerStageImpl::new(provider))
}

pub fn middleware_stage<P>(provider: P) -> Box<dyn BootstrapStage>
where
    P: MiddlewareProvider + 'static,
{
    Box::new(MiddlewareStageImpl::new(Arc::new(provider)))
}

pub fn middleware_stage_from_arc(provider: Arc<dyn MiddlewareProvider>) -> Box<dyn BootstrapStage> {
    Box::new(MiddlewareStageImpl::new(provider))
}

pub fn data_source_stage<P>(provider: P) -> Box<dyn BootstrapStage>
where
    P: DataSourceProvider + 'static,
{
    Box::new(DataSourceStageImpl::new(Arc::new(provider)))
}

pub fn data_source_stage_from_arc(provider: Arc<dyn DataSourceProvider>) -> Box<dyn BootstrapStage> {
    Box::new(DataSourceStageImpl::new(provider))
}

/// ForgeConfig 阶段包装
struct ForgeConfigStageImpl {
    provider: Arc<dyn ForgeConfigProvider>,
}

impl ForgeConfigStageImpl {
    fn new(provider: Arc<dyn ForgeConfigProvider>) -> Self {
        Self { provider }
    }
}

#[async_trait]
impl BootstrapStage for ForgeConfigStageImpl {
    fn name(&self) -> &'static str {
        self.provider.name()
    }

    async fn execute(
        &self,
        ctx: &mut BootstrapContext,
    ) -> BootstrapResult<()> {
        let config = self.provider.provide(ctx.profile()).await?;
        ctx.set_forge_config(config);
        Ok(())
    }
}

/// 快捷构造 ForgeConfig 阶段
pub fn forge_config_stage<P>(provider: P) -> Box<dyn BootstrapStage>
where
    P: ForgeConfigProvider + 'static,
{
    Box::new(ForgeConfigStageImpl::new(Arc::new(provider)))
}

pub fn forge_config_stage_from_arc(provider: Arc<dyn ForgeConfigProvider>) -> Box<dyn BootstrapStage> {
    Box::new(ForgeConfigStageImpl::new(provider))
}
